#include "BTreeIndex.h"
#include "BTreeNode.h"
#include "iostream"
using namespace std;
BTreeIndex::BTreeIndex()
{
    rootPid = -1;
	treeHeight = -1;
}
RC BTreeIndex::open(const string& indexname, char mode)
{
	openMode = mode;
    RC rc = pf.open(indexname, mode);
	char buffer[PageFile::PAGE_SIZE];
	if(pf.read(0, buffer) == 0)
	{
		rootPid = *((int*)buffer);
		treeHeight = *((int*)(buffer+4));
		return rc;
	}
	if(mode == 'r')
		return rc;
	pf.write(0, buffer);
	rootPid = 1;
	PageId leafPid = 2;
	treeHeight = 1;
	BTNonLeafNode root;
	BTLeafNode	leaf;
	root.setLeftPtr(leafPid);
	root.write(rootPid, pf);
	leaf.write(leafPid, pf);
	return rc;
}
RC BTreeIndex::close()
{
	if(openMode == 'w')
	{
		char buffer[PageFile::PAGE_SIZE];
		*((int*)buffer) = rootPid;
		*((int*)(buffer+4)) = treeHeight;
		pf.write(0, buffer); 
	}
    return pf.close();
}
RC BTreeIndex::insert(int key, const RecordId& rid)
{
    IndexCursor leafCursor;
	locate(key, leafCursor);
	BTLeafNode leaf;
	leaf.read(leafCursor.pid, pf);
	if(leaf.insert(key, rid) == 0)
	{
		leaf.write(leafCursor.pid, pf);
		return 0;
	}
	BTLeafNode sib;
	int sibKey;
	leaf.insertAndSplit(key, rid, sib, sibKey);
	PageId sibPid = pf.endPid();
	sib.setNextNodePtr(leaf.getNextNodePtr());
	leaf.setNextNodePtr(sibPid);
	leaf.write(leafCursor.pid, pf);
	sib.write(sibPid, pf);
	insertInParent(leafCursor.pid, sibKey, sibPid);
}
RC BTreeIndex::insertInParent(PageId leftPid, int midKey, PageId rightPid)
{
	if(leftPid == rootPid)
	{
		BTNonLeafNode root;
		root.setLeftPtr(leftPid);
		root.insert(midKey, rightPid);
		PageId newPid = pf.endPid();
		rootPid = newPid;
		root.write(newPid, pf);
		treeHeight++;
	}
	int height = treeHeight;
	int nodepid = rootPid;
	int parentPid = rootPid;
	BTNonLeafNode nonleaf;
	while(height > 0)
	{
		nonleaf.read(nodepid, pf);
		parentPid = nodepid;
		nonleaf.locateChildPtr(midKey, nodepid);
		if(nodepid == leftPid)
			break;
		height--;
	}
	nonleaf.read(parentPid, pf);
	if(nonleaf.insert(midKey, rightPid) == 0)
	{
		nonleaf.write(parentPid, pf);
		return 0;
	}
	BTNonLeafNode sib;
	int sibKey;
	nonleaf.insertAndSplit(midKey, rightPid, sib, sibKey);
	PageId sibPid = pf.endPid();
	nonleaf.write(parentPid, pf);
	sib.write(sibPid, pf);
	insertInParent(parentPid, sibKey, sibPid);
	
}
RC BTreeIndex::locate(int searchKey, IndexCursor& cursor)
{
	int height = treeHeight;
	int nodepid = rootPid;
	BTNonLeafNode nonleaf;
	while(height > 0)
	{
		nonleaf.read(nodepid, pf);
		nonleaf.locateChildPtr(searchKey, nodepid);
		height--;
	}
	BTLeafNode leaf;
	leaf.read(nodepid, pf);
	int entryid;
	RC rc;
	rc = leaf.locate(searchKey, entryid);
	cursor.pid = nodepid;
	cursor.eid = entryid;
	return rc;
}
RC BTreeIndex::readForward(IndexCursor& cursor, int& key, RecordId& rid)
{
    if(cursor.pid >= pf.endPid() || cursor.pid < 0)
		return RC_INVALID_CURSOR;
	BTLeafNode leaf;
	leaf.read(cursor.pid, pf);
	RC rc = leaf.readEntry(cursor.eid, key, rid);
	if(rc != 0)
		return rc;
	if(cursor.eid+1 == leaf.getKeyCount())
	{
		cursor.eid = 0;
		cursor.pid = leaf.getNextNodePtr();
		return 0;
	}
	else
	{
		cursor.eid += 1;
		return 0;
	}
}
